﻿using System;
using System.Collections.Generic;
using System.Text;
using UDS.Components;
using System.Data.SqlClient;
using System.Data;

namespace UDS.Entity
{
    public class PFDirectoryInfo
    {
        public int Id { get; set; }
        public int ParentId { get; set; }
        public int OwnerId { get; set; }
        public string Name { get; set; }
        public DateTime TimeCreated { get; set; }
        public DateTime LastModified { get; set; }

        /// <summary>
        /// Get an array of sub directories
        /// </summary>
        public PFDirectoryInfo[] Directories { get; private set; }

        /// <summary>
        /// Get an array of files in the directory
        /// </summary>
        public PFFileInfo[] Files { get; private set; }

        /// <summary>
        /// create a new directory
        /// </summary>
        /// <param name="ownerId">the id of the owner</param>
        /// <param name="parentDirectoryId">the id of its parent directory, or 0 for the root directory.</param>
        /// <param name="name">the name of the directory.</param>
        public static int CreateDirectory(int ownerId, int parentDirectoryId, string name)
        {
            var parameters = new SqlParameter[]
            {
                Database.MakeOutParam("@directoryId", System.Data.SqlDbType.Int, 4),
                Database.MakeInParam("@parentDirectoryId", System.Data.SqlDbType.Int, 4, parentDirectoryId),
                Database.MakeInParam("@name", System.Data.SqlDbType.NVarChar, 256, name),
                Database.MakeInParam("@ownerId", System.Data.SqlDbType.Int, 4, ownerId),
            };

            using (var db = new Database())
            {
                using (var tran = db.BeginTransaction())
                {
                    if (parentDirectoryId <= 0)
                    {
                        // create a root folder
                        parentDirectoryId = GetRootDirectory(db, ownerId);
                        parameters[1].Value = parentDirectoryId;
                    }

                    // create the folder now
                    db.RunProc("dbo.sproc_File_CreateUpdateDirectory_V2", parameters);
                    int folderId = (int)parameters[0].Value;
                    if (folderId <= 0)
                    {
                        throw new InvalidOperationException("Failed to create a new directory.");
                    }

                    // commits the transaction now
                    db.Commit();
                    return folderId;
                }
            }
        }

        public static void Delete(int ownerId, int directoryId)
        {
            var parameters = new SqlParameter[]
            {
                Database.MakeInParam("@ownerId", System.Data.SqlDbType.Int, 4, ownerId),
                Database.MakeInParam("@directoryId", System.Data.SqlDbType.Int, 4, directoryId)
            };

            using (var db = new Database())
            {
                db.RunProc("dbo.sproc_File_DeleteDirectory_V2", parameters);
            }
        }

        /// <summary>
        /// Get the detailed information of the given directory (or -1 for the root directory).
        /// </summary>
        public static PFDirectoryInfo GetDirectory(int ownerId, int directoryId)
        {
            var parameters = new SqlParameter[]
            {
                Database.MakeInParam("@ownerId", System.Data.SqlDbType.Int, 4, ownerId),
                Database.MakeInParam("@directoryId", System.Data.SqlDbType.Int, 4, directoryId)
            };

            using (var db = new Database())
            {
                using (var dr = db.RunDataReader("dbo.sproc_File_GetDirectoryInfo_V2", parameters))
                {
                    PFDirectoryInfo d;
                    if (!dr.Read())
                    {
                        // Not found
                        return null;
                    }

                    d = ReadDirectoryInfo(dr);

                    // read the sub directories
                    if (dr.NextResult())
                    {
                        List<PFDirectoryInfo> dirs = new List<PFDirectoryInfo>();
                        while (dr.Read())
                        {
                            dirs.Add(ReadDirectoryInfo(dr));
                        }
                        d.Directories = dirs.ToArray();

                        if (dr.NextResult())
                        {
                            // read files
                            List<PFFileInfo> files = new List<PFFileInfo>();
                            while (dr.Read())
                            {
                                PFFileInfo f = PFFileInfo.ReadFileInfo(dr);
                                f.DirectoryName = d.Name;
                                files.Add(f);
                            }
                            d.Files = files.ToArray();
                        }
                    }
                    return d;
                }
            }
        }

        internal static int GetRootDirectory(Database db, int ownerId)
        {
            var parameters = new SqlParameter[]
            {
                Database.MakeInParam("@ownerId", System.Data.SqlDbType.Int, 4, ownerId),
                Database.MakeOutParam("@directoryId", System.Data.SqlDbType.Int, 4)
            };

            db.RunProc("dbo.sproc_File_GetRootDirectory_V2", parameters);
            return (int)parameters[1].Value;
        }

        private static PFDirectoryInfo ReadDirectoryInfo(IDataReader dr)
        {
            PFDirectoryInfo d = new PFDirectoryInfo();
            d.Id = (int)dr["DirectoryId"];
            d.ParentId = (int)dr["ParentDirectoryId"];
            d.OwnerId = (int)dr["OwnerId"];
            d.Name = Convert.ToString(dr["Name"]);
            d.TimeCreated = Convert.ToDateTime(dr["TimeCreated"]);
            d.LastModified = Convert.ToDateTime(dr["LastModified"]);

            return d;
        }
    }
}
